package com.cmc.cloud.cmclink.doc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.nacos.shaded.com.google.gson.Gson;
import com.baomidou.lock.annotation.Lock4j;
import com.cmc.cloud.cmclink.common.filter.FilterGroup;
import com.cmc.cloud.cmclink.common.filter.FilterRule;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.VoyageBsaCbaDetailErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.VoyageBsaCbaErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.enums.filter.FilterConditionFieldEnum;
import com.cmc.cloud.cmclink.doc.enums.filter.util.FilterEnumUtil;
import com.cmc.cloud.cmclink.doc.rpcservice.CustomerRpcService;
import com.cmc.cloud.cmclink.doc.vo.FilterConditionVO;
import com.cmc.cloud.cmclink.doc.vo.FilterFieldVO;
import com.cmc.cloud.cmclink.doc.vo.voyagebsacbadetailvo.VoyageBsaCbaDetailBaseVO;
import com.cmc.cloud.cmclink.doc.vo.voyagebsacbadetailvo.VoyageBsaCbaDetailCreateReqVO;
import com.cmc.cloud.cmclink.doc.vo.voyagebsacbadetailvo.VoyageBsaCbaDetailPageReqVO;
import com.cmc.cloud.cmclink.doc.vo.voyagebsacbadetailvo.VoyageBsaCbaDetailRespVO;
import com.cmc.cloud.cmclink.doc.vo.voyagebsacbadetailvo.VoyageBsaCbaDetailUpdateReqVO;
import com.cmc.cloud.cmclink.doc.vo.voyagebsacbadetailvo.VoyageCbaDetailBatchVO;
import com.cmes.framework.mybatis.core.query.LambdaQueryWrapperX;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import com.cmes.framework.common.pojo.PageResult;
import com.cmes.framework.common.exception.util.ServiceExceptionUtil;

import java.util.*;import java.util.stream.Collectors;

import com.cmc.cloud.cmclink.doc.service.VoyageBsaCbaDetailService;
import com.cmc.cloud.cmclink.doc.entity.VoyageBsaCbaDetailDO;
import com.cmc.cloud.cmclink.doc.mapper.VoyageBsaCbaDetailMapper;
import com.cmc.cloud.cmclink.common.filter.enums.*;


/**
 * 分类舱位自动批舱匹配条件 Service 实现类
 *
 * @author 集运管理员
 */
@Service
@Validated
public class VoyageBsaCbaDetailServiceImpl implements VoyageBsaCbaDetailService {
    public static final String COMMA = ",";

    @Resource
    private VoyageBsaCbaDetailMapper voyageBsaCbaDetailMapper;

    @Resource
    private CustomerRpcService nameTransferService;

    private final Gson gson = new Gson();

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Lock4j(name = "voyageBsaCbaDetailUnique", keys = {"#createReqVO.getVoyageBsaCbaId", "#createReqVO.getFilterGroup.toString"})
    public void createVoyageBsaCbaDetail(VoyageBsaCbaDetailCreateReqVO createReqVO) {
        validateUniqueExists(createReqVO, null);
        VoyageBsaCbaDetailDO voyageBsaCbaDetail = BeanUtil.copyProperties(createReqVO, VoyageBsaCbaDetailDO.class);
        voyageBsaCbaDetail.setJsonString(gson.toJson(createReqVO.getFilterGroup()));
        voyageBsaCbaDetailMapper.insert(voyageBsaCbaDetail);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Lock4j(name = "voyageBsaCbaDetailUnique", keys = {"#updateReqVO.getVoyageBsaCbaId", "#updateReqVO.getFilterGroup.toString"})
    public void updateVoyageBsaCbaDetail(VoyageBsaCbaDetailUpdateReqVO updateReqVO) {
        // 校验存在
        validateVoyageBsaCbaDetailExists(updateReqVO.getId());
        validateUniqueExists(updateReqVO, updateReqVO.getId());
        // 更新
        VoyageBsaCbaDetailDO updateObj = BeanUtil.copyProperties(updateReqVO, VoyageBsaCbaDetailDO.class);
        updateObj.setJsonString(gson.toJson(updateReqVO.getFilterGroup()));
        voyageBsaCbaDetailMapper.updateById(updateObj);
    }

    @Override
    public void deleteVoyageBsaCbaDetail(Long id) {
        // 校验存在
        validateVoyageBsaCbaDetailExists(id);
        // 删除
        voyageBsaCbaDetailMapper.deleteById(id);
    }

    private void validateVoyageBsaCbaDetailExists(Long id) {
        if (voyageBsaCbaDetailMapper.selectById(id) == null) {
            throw ServiceExceptionUtil.exception(VoyageBsaCbaDetailErrorCodeConstants.VOYAGE_BSA_CBA_DETAIL_NOT_EXISTS);
        }
    }

    private void validateUniqueExists(VoyageBsaCbaDetailBaseVO vo, Long id) {
        LambdaQueryWrapperX<VoyageBsaCbaDetailDO> queryWrapperX = new LambdaQueryWrapperX<VoyageBsaCbaDetailDO>()
                .eqIfPresent(VoyageBsaCbaDetailDO::getVoyageBsaCbaId, vo.getVoyageBsaCbaId());
        if (id != null) {
            queryWrapperX.ne(VoyageBsaCbaDetailDO::getId, id);
            queryWrapperX.eqIfPresent(VoyageBsaCbaDetailDO::getJsonString, gson.toJson(vo.getFilterGroup()));
        }
        if (voyageBsaCbaDetailMapper.selectCount(queryWrapperX) != 0L) {
            throw ServiceExceptionUtil.exception(VoyageBsaCbaDetailErrorCodeConstants.VOYAGE_BSA_CBA_DETAIL_EXISTED);
        }
    }

    @Override
    public VoyageBsaCbaDetailDO getVoyageBsaCbaDetail(Long id) {
        return voyageBsaCbaDetailMapper.selectById(id);
    }

    @Override
    public VoyageBsaCbaDetailRespVO getByMainId(Long voyageBsaCbaId) {
        VoyageBsaCbaDetailDO voyageBsaCbaDetailDO = voyageBsaCbaDetailMapper.selectOne(new LambdaQueryWrapperX<VoyageBsaCbaDetailDO>().eq(VoyageBsaCbaDetailDO::getVoyageBsaCbaId, voyageBsaCbaId));
        if (voyageBsaCbaDetailDO == null) {
            return new VoyageBsaCbaDetailRespVO();
        }
        VoyageBsaCbaDetailRespVO voyageBsaCbaDetailRespVO = BeanUtil.copyProperties(voyageBsaCbaDetailDO, VoyageBsaCbaDetailRespVO.class);
        voyageBsaCbaDetailRespVO.setFilterGroup(gson.fromJson(voyageBsaCbaDetailDO.getJsonString(), FilterGroup.class));

        List<String> bkpCodeValues = Optional.ofNullable(voyageBsaCbaDetailRespVO).map(VoyageBsaCbaDetailRespVO::getFilterGroup).map(FilterGroup::getFilterRules).orElse(Collections.emptyList())
                .stream().filter(f -> f != null && f.getFieldName().equals(FilterConditionFieldEnum.BKP_CODE.getFieldName())).map(FilterRule::getValue).collect(Collectors.toList());
        if (!CollectionUtil.isEmpty(bkpCodeValues)){
            ArrayList<String> strings = new ArrayList<>();
            bkpCodeValues.forEach(t -> {
                String[] split = t.split(COMMA);
                strings.addAll(Arrays.asList(split));
            });
            voyageBsaCbaDetailRespVO.setBkpMap(nameTransferService.getCompanyNameMap(strings));
        }

        return voyageBsaCbaDetailRespVO;
    }

    @Override
    public List<VoyageBsaCbaDetailDO> getVoyageBsaCbaDetailList(Collection<Long> ids) {
        return voyageBsaCbaDetailMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<VoyageBsaCbaDetailDO> getVoyageBsaCbaDetailPage(VoyageBsaCbaDetailPageReqVO reqVO) {
        IPage<VoyageBsaCbaDetailDO> page = Page.of(reqVO.getPageNo(), reqVO.getPageSize());

        IPage<VoyageBsaCbaDetailDO> result = voyageBsaCbaDetailMapper.selectPageList(page, reqVO);
        return new PageResult<VoyageBsaCbaDetailDO>(result.getRecords(), result.getTotal());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchSaveDetail(VoyageCbaDetailBatchVO detailBatchVO) {
        LambdaQueryWrapperX<VoyageBsaCbaDetailDO> queryWrapperX = new LambdaQueryWrapperX<VoyageBsaCbaDetailDO>()
                .inIfPresent(VoyageBsaCbaDetailDO::getVoyageBsaCbaId, detailBatchVO.getVoyageBsaCbaIds());
        List<VoyageBsaCbaDetailDO> detailDOList = voyageBsaCbaDetailMapper.selectList(queryWrapperX);
        if (CollectionUtil.isNotEmpty(detailDOList)) {
            if (detailDOList.size() != detailBatchVO.getVoyageBsaCbaIds().size()) {
                //如果存在 未配置规则的分类舱位 不允许操作
                throw ServiceExceptionUtil.exception(VoyageBsaCbaErrorCodeConstants.VOYAGE_BSA_CBA_DETAIL_NOT_EXISTS);
            }
            FilterGroup addGroup = detailBatchVO.getFilterGroup();
            if (CollectionUtil.isEmpty(addGroup.getFilterRules())) {
                throw ServiceExceptionUtil.exception(VoyageBsaCbaErrorCodeConstants.VOYAGE_BSA_CBA_DETAIL_LIST_EMPTY);
            }
            detailDOList.forEach(entity -> {
                FilterGroup filterGroup = gson.fromJson(entity.getJsonString(), FilterGroup.class);
                switch (filterGroup.getFilterType()) {
                    //增量层为 and  原有规则最外层为 and
                    case AND:
                        List<FilterRule> filterRules = filterGroup.getFilterRules();
                        filterRules.addAll(addGroup.getFilterRules());
                        filterGroup.setFilterRules(filterRules);
                        entity.setJsonString(gson.toJson(filterGroup));
                        break;
                    case OR:
                        //校验层数 目前前端组件只支持套两层groups
                        if (CollectionUtil.isNotEmpty(filterGroup.getFilterGroups())) {
                            if (filterGroup.getFilterGroups().stream().filter(vo -> CollectionUtil.isNotEmpty(vo.getFilterGroups())).findAny().isPresent()) {
                                throw ServiceExceptionUtil.exception(VoyageBsaCbaErrorCodeConstants.VOYAGE_BSA_CBA_LAYER_ERROR);
                            }
                        }
                        //增量层为 and  原有规则最外层为 or
                        FilterGroup newFilterGroup = new FilterGroup();
                        newFilterGroup.setFilterType(FilterCombineType.AND);
                        newFilterGroup.setFilterRules(addGroup.getFilterRules());
                        List<FilterGroup> innerGroupList = CollectionUtil.newArrayList();
                        innerGroupList.add(filterGroup);
                        newFilterGroup.setFilterGroups(innerGroupList);
                        entity.setJsonString(gson.toJson(newFilterGroup));
                        break;
                    default:
                        throw ServiceExceptionUtil.exception(VoyageBsaCbaErrorCodeConstants.VOYAGE_BSA_CBA_LOGICAL_ILLEGAL);
                }
            });
            voyageBsaCbaDetailMapper.saveOrUpdateBatch(detailDOList);
        }
    }

    @Override
    public List<FilterFieldVO> getFilterInfo(String enumType, String keyWord) {
        return FilterEnumUtil.getFilterInfo(enumType, keyWord);
    }

    @Override
    public List<FilterConditionVO> getFilterConditionInfo(String keyWord) {
        return FilterEnumUtil.getFilterConditionInfo(keyWord);
    }
}
